﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Samurai.Validation.Specs.StaticMocks;
using Samurai.Wakizashi.Validation;

namespace Samurai.Validation.Specs
{
    [TestClass]
    public class Validator_Specification
    {
        [TestMethod]
        public void Provides_newly_created_instance_of_Validator()
        {
            var c = new Customer();
            Assert.IsNotNull(Validator<Customer>.Create(c));
        }

        [TestMethod]
        public void Analyzes_target_provided_upon_validator_creation()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            Assert.IsTrue(validator.GetRulesForProperty("Age").Count > 0);
        }

        [TestMethod]
        public void Allows_dynamic_application_of_rule_to_property()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            var rule = new FakeRule();
            validator.Apply(rule).To("TestProperty");

            Assert.IsTrue(validator.GetRulesForProperty("TestProperty").Contains(rule));
        }

        [TestMethod]
        public void Executes_all_rules_applied_to_target_property()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            var rule = new FakeRule();
            var rule2 = new FakeRule();
            validator.Apply(rule).To("TestProperty");
            validator.Apply(rule2).To("TestProperty");

            var result = validator.Validate("TestProperty");

            Assert.IsTrue(rule.ValidateWasCalled && rule2.ValidateWasCalled);
        }

        [TestMethod]
        public void Executes_all_rules_applied_to_all_properties_on_target_object()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            var rule = new FakeRule();
            var rule2 = new FakeRule();
            validator.Apply(rule).To("TestProperty");
            validator.Apply(rule2).To("TestProperty");

            var result = validator.Validate();

            Assert.IsTrue(rule.ValidateWasCalled && rule2.ValidateWasCalled);
        }

        [TestMethod]
        public void Provides_messages_for_all_failed_rules()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            var rule = new FakeRule();
            var rule2 = new FakeRule();
            validator.Apply(rule).To("TestProperty");
            validator.Apply(rule2).To("TestProperty");

            var result = validator.Validate();

            Assert.IsTrue(result.InvalidProperties.Count > 0 && result.InvalidProperties["TestProperty"].Length == 2);
        }

        [TestMethod]
        public void Supplies_reasons_for_rules_that_do_not_pass_validation()
        {
            var c = new Customer();
            var validator = Validator<Customer>.Create(c);

            var rule = new FakeRule();
            var rule2 = new FakeRule();
            validator.Apply(rule).To("TestProperty");
            validator.Apply(rule2).To("TestProperty");

            var result = validator.Validate("TestProperty");

            Assert.IsTrue(result.IsValid == false && result.InvalidProperties.Count > 0 && result.InvalidProperties["TestProperty"].Length == 2);
        }

        [TestMethod]
        public void Wires_up_instance_to_property_map()
        {
            var customer = new Customer();
            var validator = Validator<Customer>.Create(customer);

            var rules = validator.GetRulesForProperty(customer.GetType().GetProperty("Age"));
            Assert.IsNotNull(rules[0].PropertyUnderValidation.Owner);
        }

        [TestMethod]
        public void Allows_flushing_of_all_applied_rules()
        {
            var c = new Customer {LastName = "Doe"};
            var v = Validator<Customer>.Create(c);
            v.FlushRules();

            Assert.IsTrue(v.GetRulesForProperty("FirstName").Count == 0);
        }
    }
}
